package com.nova.bluetooth.xunFeiSDK.engine;




import static com.nova.bluetooth.xunFeiSDK.engine.EngineConstants.mAIUIState;
import static com.nova.bluetooth.xunFeiSDK.engine.EngineConstants.saveAudio;
import static com.nova.bluetooth.xunFeiSDK.engine.EngineConstants.serialNumber;
import static com.nova.bluetooth.xunFeiSDK.engine.EngineConstants.wakeEngineLogLevel;
import static com.nova.bluetooth.xunFeiSDK.engine.EngineConstants.wakeupEngineDir;

import android.util.Log;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.android.exoplayer2.C;
import com.iflytek.aiui.AIUIConstant;
import com.iflytek.iflyos.cae.CAE;
import com.iflytek.iflyos.cae.ICAEListener;
import com.nova.bluetooth.xunFeiSDK.utils.AudioAmplify;
import com.nova.bluetooth.xunFeiSDK.utils.ErrorCode;
import com.nova.bluetooth.xunFeiSDK.utils.FileUtil;
import com.nova.bluetooth.xunFeiSDK.utils.SoundPoolUtil;


public class WakeupEngine {
    private static final String TAG = WakeupEngine.class.getSimpleName();
    private static WakeupEngine wakeupEngine;
    //vtn.ini配置文件的路径
    public static String cfgPath = "resources/config/vtn.ini";
    // 信息透传回调监听
    private static WakeupListener wakeupListener;

    private WakeupEngine() {
    }

    //单例模式
    public static WakeupEngine getInstance(WakeupListener wakeupListener) {
        // 检查对象是否存在,不存在就进入同步区块
        if (wakeupEngine == null) {
            // 同步区块里面的代码只有在第一次才会执行
            synchronized (WakeupEngine.class) {
                if (wakeupEngine == null) {
                    WakeupEngine.wakeupListener = wakeupListener;
                    CAE.loadLib();
                    //唤醒引擎读取通用配置
                    String configPath = String.format("%s/%s", wakeupEngineDir, cfgPath);
                    int result = CAE.CAENew(serialNumber, configPath, mCAEListener);
                    if (result == 0) {
                        wakeupEngine = new WakeupEngine();
                        Log.i(TAG, "CAE初始化成功");
                    } else {
                        Log.e(TAG, "CAE初始化失败,错误码：" + result);
                        Log.e(TAG, "解决方案：" + ErrorCode.getError(result) + " \n 错误解决详情参考：https://www.yuque.com/iflyaiui/zzoolv/igbuol");
                    }
                    // Alsa-Jni日志控制 1(debug) 2(info) 3(warn) 4(error) 5(fatal)
                    CAE.CAESetShowLog(wakeEngineLogLevel);
                }
            }
        }
        Log.i(TAG, "return wakeupEngine");
        return wakeupEngine;
    }

    // CAE-SDK 结果回调监听器
    static ICAEListener mCAEListener = new ICAEListener() {
        //降噪后音频送去识别，16k，16bit，1声道
        @Override
        public void onAudioCallback(byte[] caeOutputAudio, int length) {
            // CAE降噪后音频写入AIUI SDK,AIUI内部用VAD过滤无效音频，再送到云端识别

            if (AIUIConstant.STATE_WORKING == mAIUIState && EngineConstants.wakeupType == EngineConstants.WAKEUPTYPE_VOICE) {
                //改变识别音频增益
                if (EngineConstants.asrAudioGain != 1.0f) {
                    AudioAmplify.amplifyAll(caeOutputAudio, EngineConstants.asrAudioGain);
                }
                AiuiEngine.MSG_writeAudio(caeOutputAudio);
            }
            //保存识别音频
            if (saveAudio) {
                FileUtil.writeFile(caeOutputAudio, "/sdcard/asr.pcm");
            }
        }

        @Override
        public void onIvwAudioCallback(byte[] bytes, int i) {
            //保存唤醒+识别音频，一般不需要处理
        }

        @Override
        public void onWakeup(String result) {
            JSONObject wakeupResult = JSON.parseObject(result).getJSONObject("ivw");
            int physicalBeam = wakeupResult.getInteger("physical"); //波束
            int score = wakeupResult.getInteger("score");           //唤醒得分，得分>阈值才会抛出唤醒
            int angle = wakeupResult.getInteger("angle");           //唤醒角度
            String keyWord = wakeupResult.getString("keyword"); //唤醒词
            Log.i(TAG, "唤醒成功,angle:" + angle + " beam:" + physicalBeam + " score=" + score + " 唤醒词" + keyWord);
            //唤醒后播放提示音或用灯光，UI响应
            SoundPoolUtil.play("唤醒提示音");
            //唤醒后给AIUI SDK发送唤醒事件：让AIUI SDK工作
            AiuiEngine.MSG_wakeup(EngineConstants.WAKEUPTYPE_VOICE);

//            //**************唤醒词+命令词执行逻辑**************
//            //不同唤醒词keyword对应不同功能，根据实际修改
//            if (keyWord.contains("xiao3-fei1-xiao3-fei1")) {
//                //有网络才进行识别
//                if (Network.isNetSystemUsable()) {
//                    //唤醒后播放提示音或用灯光，UI响应
//                    SoundPoolUtil.play("唤醒提示音");
//                    //唤醒后给AIUI SDK发送唤醒事件：让AIUI SDK工作
//                    AiuiEngine.MSG_wakeup(AiuiUtils.WAKEUPTYPE_VOICE);
//                } else {
//                    //无网络,播放提示
//                    SoundPoolUtil.play("未联网提示音");
//                }
//            }
//            //命令词执行逻辑
//            else {
//                if (!Network.isNetSystemUsable()) {
//                    //未联网状态才执行命令词。联网状态用在线结果，这里不处理
//                }
//            }
//            //**************唤醒词+命令词执行逻辑**************


            //回调唤醒结果给上层
            wakeupListener.onWakeup(angle, physicalBeam, score, keyWord);
        }
    };

    public static void destroy() {
        if (wakeupEngine != null) {
            wakeupEngine = null;
            CAE.CAEDestory();
            Log.i(TAG, "销毁wakeupEngine");
        }
    }

    // 外部音频写入唤醒引擎进行降噪和唤醒
    public static void writeAudioToCAE(byte[] data) {
        if (wakeupEngine != null) {
            CAE.CAEAudioWrite(data, data.length);
        } else {
//            Log.e(TAG, "wakeupEngine未初始化");
        }
    }

    // 拾音波束方向，语音唤醒后自动处理，手动唤醒需要根据具体方向调用
    public static void setRealBeam(int beam) {
        CAE.CAESetRealBeam(beam);
    }

    // 获取CAE版本
    public static String getCAEVersion() {
        return CAE.CAEGetVersion();
    }

    /**
     * 动态替换唤醒词
     *
     * @param wakewordBinPath 唤醒资源路径，示例：/sdcard/vtn/cae/res.bin
     * @return
     */
    public static int reloadWakeResource(String wakewordBinPath) {
        if (wakeupEngine != null) {
            return CAE.CAEReloadResource(wakewordBinPath);
        } else {
            Log.e(TAG, "wakeupEngine未初始化");
            return -1;
        }
    }
}
